org 0x7c00

jmp short start
nop

define:
	BaseOfStack  	 equ 0x7c00
	BaseOfLoader     equ 0x9000
	Bytes_RootEntry  equ 32
	RootEntryOffset	 equ 19
	RootEntryLength	 equ 14
	EntryItemLength  equ 32
	FatEntryOffset   equ 1
	DIRFstClusOffset equ 0x1A

header:
	BS_OEMName 		db  'FreeDOS '
	BPB_BytsPerSec  dw  512
	BPB_SecPerClus	db  1
	BPB_RsvdSecCnt	dw  1
	BPB_NumFATs		db  2
	BPB_RootEntCnt	dw  224
	BPB_TotSec16	dw  2880
	BPB_Media		db  0xF0
	BPB_FATSz16		dw  9
	BPB_SecPerTrk	dw  18
	BPB_NumHeads	dw  2
	BPB_HiddSec		dd  0
	BPB_TotSec32	dd  0
	BS_DrvNum		db  0
	BS_Reserved1	db  0
	BS_BootSig		db  0x29
	BS_VolID		dd  0
	BS_VolLab		db 	'OS-0.01    '
	BS_FileSysType	db  'FAT12   '

start:
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, BaseOfStack

;找到Loader表项并复制到指定内存
	mov ax, RootEntryOffset
	mov cx, RootEntryLength
	mov bx, buf

	call ReadSector

	mov si, Target
	mov cx, TargetLen
	mov dx, 0

	call FindEntry
	cmp dx, 0
	jz noEntry
	
	mov si, bx
	mov di, EntryItem
	mov cx, EntryItemLength
	call MemCpy

;加载fat表
	mov bx, [BPB_FATSz16]
	mov ax, [BPB_BytsPerSec]
	mul bx
	mov bx, BaseOfLoader
	sub bx, ax

	mov ax, FatEntryOffset
	mov cx, [BPB_FATSz16]
	call ReadSector

;加载Loader
	mov si, bx
	mov bx, EntryItem
	mov ax, [bx+DIRFstClusOffset]
	mov bx, BaseOfLoader
load:
	push ax
	add ax, 31
	mov cx, 1
	call ReadSector
	pop ax
	call ReadFat
	mov ax, dx
	add bx, 512
	cmp dx, 0xff7
	jb load

	jmp BaseOfLoader

noEntry:
	mov bp, MsgStr
	mov cx, MsgLen

	call Print

last:
    hlt
    jmp last

;-------------------------func------------------------------------
; es:bx --> root entry offset address
; ds:si --> target string
; cx    --> target length
; 
; return:
;		(dx != 0) ? exit : unexit
;			exit --> bx is the target entry
FindEntry:
	push bp
	push di
	push cx

	mov dx, [BPB_RootEntCnt]
	mov bp, sp

find:
	cmp dx, 0
	jz unexit
	mov di, bx
	mov cx, [bp]
	call MemCmp
	cmp cx, 0
	jz exit
	dec dx
	add bx, Bytes_RootEntry
	jmp find

unexit:
exit:
	pop cx
	pop di
	pop bp

	ret

; cx --> str length
; es:bp --> str address
Print:
	push ax
	push bx
	push dx

	mov dx, 0     ; (0, 0)
	mov ax, 0x1301
	mov bx, 0x0007
	int 0x10

	pop dx
	pop bx
	pop ax

	ret

; no parameter
ResetFloppy:
	push ax
	push dx

	mov ah, 0x00
	mov dl, [BS_DrvNum]
	int 0x13

	pop dx
	pop ax

	ret

; ax 		--> logic sector number
; cx 		--> number of sector
; es:bx		--> target address
ReadSector:
	call ResetFloppy

	push bx
	push cx
	push dx
	push ax

	push cx
	push bx	

	mov bl, [BPB_SecPerTrk]
	div bl
	mov cl, ah
	inc cl       		;sector number
	mov ch, al
	shr ch, 1        	;cylinder number
	mov dh, al
	and dh, 1    		;head number
	mov dl, [BS_DrvNum] ;DrvNum

	pop bx				;target address
	pop ax				;read length

	mov ah, 0x02

read:
	int 0x13
	jc read				;read error

	pop ax
	pop dx
	pop cx
	pop bx

	ret

;ds:si --> source
;es:di --> destination
;cx --> length
;return 
;		(cx == 0) ? equal : unequal
MemCmp:
	push si
	push di
	cld
repz cmpsb
	pop di
	pop si
	ret

;si: source
;di: destination
;cx: length
MemCpy:
	push si
	push di
	push cx

	cmp si, di
	jb etob
btoe:
	cld
rep movsb
	jmp exitMemCpy
etob:
	add si, cx
	dec si
	add di, cx
	dec di
	std
rep movsb
exitMemCpy:
	pop cx
	pop di
	pop si

	ret

;ax:Clus
;si:fat address
;return:
;	dx:next Clus
ReadFat:
	push ax
	push si
	push cx
	push bx

	mov dx, 0
	mov cx, 2
	div cx
	push dx
	mov cx, 3
	mul cx
	pop dx
	test dx, 0x01
	jz even
odd: ;nClus = ( (Fat[i+1] >> 4)& 0x0F ) | (Fat[i+2] << 4)
	mov bx, ax
    mov bx, [bx+si+1]
    mov cl, 4
    shr bl, cl
    and bl, 0x0F
    mov dx, 0
    mov dl, bh
    mov cl, 4
    shl dx, cl
    or  dl, bl
	jmp eixtReadFat
even: ;nClus = ( (Fat[i+1] & 0x0F) << 8 ) | Fat[i]
	mov bx, ax
	mov bx, [bx+si]
	mov dx, 0
	mov dh, bh
	and dh, 0x0F
	mov dl, bl
eixtReadFat:
	pop bx
	pop cx
	pop si
	pop ax

	ret

MsgStr db "No LOADER! "
MsgLen equ ($-MsgStr)
Target db "LOADER     "
TargetLen equ ($-Target)
EntryItem times EntryItemLength db 0x00 
buf:
	times 510-($-$$) db 0x00
	db 0x55, 0xaa
